package top.xcxdl.rural.controller.user;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import top.xcxdl.rural.common.Res;
import top.xcxdl.rural.common.ResponseData;
import top.xcxdl.rural.config.consts.WxConst;
import top.xcxdl.rural.config.initexception.ErrorEnum;
import top.xcxdl.rural.config.jwtconfig.JwtConfigProperties;
import top.xcxdl.rural.entity.*;
import top.xcxdl.rural.service.*;
import top.xcxdl.rural.utils.*;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 *
 * @Author : Ding
 * @create 2022/5/16 17:58
 */
@Log4j2
@CrossOrigin
@Api("小程序接口控制器")
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IRuralUserService userService;

    @Resource
    private IRuralProductService productService;

    @Resource
    private IRuralResourceService resourceService;

    @Resource
    private JwtConfigProperties jwtConfigProperties;

    @Resource
    private IRuralCourseService courseService;

    @Resource
    private IRuralCourseUserService courseUserService;

    @Resource
    private IRuralTabService tabService;

    @Resource
    private IRuralExaminationService examinationService;

    @Resource
    private IRuralExamQuestionService examQuestionService;

    @Resource
    private IRuralQuestionService questionService;

    @Resource
    private IRuralAreaService areaService;

    /**
     * 微信授权登录
     *
     * @param openid   微信用户与小程序生成的唯一id
     * @param avatar   头像地址
     * @param nickname 昵称
     * @return res
     */
    @ApiOperation("微信登录授权")
    @ResponseBody
    @PostMapping("/toLoginByWechat")
    public Res<JSONObject> toLoginByWechat(@RequestParam(name = "openid", defaultValue = "") String openid,
                                           @RequestParam(name = "avatar", defaultValue = "") String avatar,
                                           @RequestParam(name = "nickname", defaultValue = "") String nickname) {
        RuralUser user = userService.getUserByOpenId(openid);
        if ("".equals(openid)) {
            //登录缺失必要参数-openid
            return Res.error(ErrorEnum.LOGIN_MISSING_PARAM);
        }
        //根据openid查询不到用户，则用户一定没有通过微信授权登录过
        if (user == null) {
            //添加头像--mybatisPlus会把id自动传给当前resource对象
            RuralResource resource = new RuralResource();
            resource.setUrl(avatar);
            resourceService.toAddItem(resource);
            //组装user对象信息
            RuralUser newUser = new RuralUser();
            newUser.setWxOpenid(openid);
            newUser.setUserAvatar(resource.getRId());
            newUser.setUserNickname(nickname);
            if (userService.toInsertUser(newUser) > 0) {
                RuralUser user1 = userService.getUserByOpenId(openid);
                //组装返回数据（由dealJson做处理，封装电话和token，生成与更新sig）
                log.info("用户{}（ID为{}）使用微信授权注册成功（首次登录）",user1.getUserNickname(),user1.getUserId());
                return Res.success(dealJson(user1), "注册成功");
            } else {
                return Res.error();
            }
        } else {
            //老用户登录
            if (user.getUserStatus() == 0) {
                //被强制禁用，须联系管理员
                log.info("用户{}（ID为{}）使用微信授权登录被拒，因为账户已被禁用",user.getUserNickname(),user.getUserId());
                return Res.error(ErrorEnum.LOGIN_ACCOUNT_DISABLED);
            } else {
                //组装返回数据（由dealJson做处理，封装电话和token，生成与更新sig）
                log.info("用户{}（ID为{}）使用微信授权登录成功",user.getUserNickname(),user.getUserId());
                return Res.success(dealJson(user), "登录成功");
            }
        }
    }

    /**
     * 处理用户数据信息
     * 封装电话和token，生成与更新sig
     *
     * @param user 用户对象
     * @return json
     */
    private JSONObject dealJson(RuralUser user) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("u_tel", user.getUserTel());
        jsonObject.put("token", JWTUtils.sign(String.valueOf(user.getUserId()),"0",user.getUserNickname(), jwtConfigProperties));
        //生成userSig
        String userSig = TimUtils.getUserSig(user.getWxOpenid());
        user.setTimUserSig(userSig);
        user.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
        //更新userSig
        userService.toUpdateUser(user);
        return jsonObject;
    }

    /**
     * 获取微信OpenId
     *
     * @param code 微信提供的识别码
     * @return json
     */
    @ApiOperation("获取微信OpenId")
    @ResponseBody
    @PostMapping("/getOpenId")
    public JSONObject getOpenId(@RequestParam("code") String code) {

        Map<String, String> requestUrlParam = new HashMap<String, String>();
        //开发者设置中的appId
        requestUrlParam.put("appid", WxConst.APP_ID);
        //开发者设置中的appSecret
        requestUrlParam.put("secret", WxConst.APP_SECRET);
        //小程序调用wx.login返回的code
        requestUrlParam.put("js_code", String.valueOf(code));
        //默认参数
        requestUrlParam.put("grant_type", "authorization_code");
        //发送post请求读取调用微信 https://api.weixin.qq.com/sns/jscode2session 接口获取openid用户唯一标识
        return JSON.parseObject(UrlUtil.sendPost(WxConst.WX_GET_OPENID_URL, requestUrlParam));
    }

    /**
     * 获取用户详情信息
     *
     * @return res
     */
    @ApiOperation("获取用户详情信息")
    @ResponseBody
    @GetMapping("/getUserInfo")
    public Res<RuralUser> getUserInfo() {
        return Res.success(userService.getUserById(JWTUtils.getAuthorId()));
    }

    /**
     * 用户获取消息列表（除自己外的所有用户）
     *
     * @return responseData
     */
    @GetMapping("/getFriendList")
    public ResponseData<List<RuralUser>> getFriendList() {
        // 获取好友列表，这里做简单处理，所有用户，除了自己以外，都算好友
        Integer loginUserId = JWTUtils.getAuthorId();
        List<RuralUser> list = userService.getFriendListById(loginUserId);
        return ResponseData.ok(list);
    }


    /**
     * 用户获取目标用户的信息
     *
     * @param id 目标用户id
     * @return responseData
     */
    @GetMapping("/getUserById")
    public ResponseData<RuralUser> getUser(@RequestParam("user_id") Integer id) {
        RuralUser user = userService.getUserById(id);
        return ResponseData.ok(user);
    }

    /**
     * 用户获取产品详情
     *
     * @param productId 产品id
     * @return 产品详情实体
     */
    @ApiOperation("用户获取产品详情")
    @GetMapping("/getDetail")
    @ResponseBody
    public Res<RuralProduct> getDetail(@RequestParam(name = "product_id") Integer productId) {
        RuralProduct product = productService.getDetail(productId);
        return Res.success(product);
    }

    /**
     * 获取产品列表
     *
     * @param pageNo   页码
     * @param pageSize 每页数量
     * @param key      搜索关键字
     * @return 产品列表
     */
    @GetMapping("/getProductList")
    public Res<PageInfo<RuralProduct>> getProductList(
            @RequestParam(name = "page_no", required = true) Integer pageNo,
            @RequestParam(name = "page_size", required = true) Integer pageSize,
            @RequestParam(name = "title", required = false) String key
    ) {
        PageInfo<RuralProduct> pageInfo = productService.getProductListByUser(pageNo, pageSize, key);
        return Res.success(pageInfo);
    }

    /**
     * 获取某一用户发布的产品列表
     *
     * @param pageNo     页码
     * @param pageSize   每页数量
     * @param authorType 用户类型(0:普通用户,1:管理员)
     * @param authorId   用户id（-1即本人）
     * @param key        搜索关键字
     * @return 产品列表
     */
    @GetMapping("/getProductListByUser")
    public Res<PageInfo<RuralProduct>> getProductListByUser(
            @RequestParam(name = "page_no", required = true) Integer pageNo,
            @RequestParam(name = "page_size", required = true) Integer pageSize,
            @RequestParam(name = "author_type", required = true) Integer authorType,
            @RequestParam(name = "author_id", required = true) Integer authorId,
            @RequestParam(name = "title", required = false) String key
    ) {
        Integer userId = authorId == -1 ? JWTUtils.getAuthorId() : authorId;
        PageInfo<RuralProduct> pageInfo = productService.getProductListByUserId(pageNo, pageSize, userId, authorType, key);
        return Res.success(pageInfo);
    }

    /**
     * 用户新增 or 修改（处理）产品宣传信息
     *
     * @param product 商品实体
     * @return Res
     */
    @PostMapping("/doAddProduct")
    @ApiOperation("用户新增 or 修改（处理）产品宣传信息")
    @ResponseBody
    public Res<Object> doAddProduct(
            @RequestBody RuralProduct product) {
        int ret = 0;
        Integer id = product.getProductId();
        if (id == null) {
            //新增,设置创建人
            Integer userId = JWTUtils.getAuthorId();
            product.setAuthorType(0);
            product.setAuthorId(userId);
            product.setProductStatus(0);
        }
        ret += productService.doEdit(product);
        return ret > 0 ? Res.success(id == null ? "添加成功" : "编辑成功") : Res.error("操作失败");
    }


    /**
     * 用户查询课程列表
     *
     * @param pageNo   页码
     * @param pageSize 每页数量
     * @param key      搜索关键字
     * @return 课程列表
     */
    @GetMapping("/getCourseList")
    @ApiOperation("获取课程列表")
    @ResponseBody
    public Res<Object> getList(
            @RequestParam(name = "page_no") Integer pageNo,
            @RequestParam(name = "page_size") Integer pageSize,
            @RequestParam(name = "title", required = false) String key
    ) {
        Integer userId = JWTUtils.getAuthorId();
        PageInfo<RuralCourse> pageInfo = courseService.getListByUser(pageNo, pageSize, userId, key);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return Res.success(jsonObject);
    }

    /**
     * 用户查询"我的课程"列表
     *
     * @param pageNo   页码
     * @param pageSize 每页数量
     * @param key      搜索关键字
     * @return 课程列表
     */
    @GetMapping("/getCollectedCourseList")
    @ApiOperation("获取课程列表")
    @ResponseBody
    public Res<Object> getCourseListWhereCollected(
            @RequestParam(name = "page_no") Integer pageNo,
            @RequestParam(name = "page_size") Integer pageSize,
            @RequestParam(name = "title", required = false) String key
    ) {
        Integer userId = JWTUtils.getAuthorId();
        PageInfo<RuralCourse> pageInfo = courseService.getCourseListWhereCollected(pageNo, pageSize, userId, key);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("list", pageInfo.getList());
        jsonObject.put("total", pageInfo.getTotal());
        return Res.success(jsonObject);
    }

    /**
     * 用户查看课程详情
     * 用户未报名课程只会获取部分信息
     *
     * @param courseId 课程id
     * @return 课程实体
     */
    @GetMapping("/getCourseDetail")
    @ApiOperation("获取课程详情")
    @ResponseBody
    public Res<Object> getCourseDetail(
            @RequestParam(name = "course_id", required = true) Integer courseId
    ) {
        //如果课程关闭，则直接返回空
        if(courseService.getById(courseId).getClassStatus() == 0){
            return Res.error(new RuralCourse(),"该课程尚未开放");
        }
        //获取用户id
        Integer userId = JWTUtils.getAuthorId();
        //获取用户与课程关联状态
        RuralCourseUser ruralCourseUser = new RuralCourseUser();
        ruralCourseUser.setUserId(userId);
        ruralCourseUser.setCourseId(courseId);
        boolean isCollected = courseUserService.isExists(ruralCourseUser);
        //根据是否报课，查询不同数据
        RuralCourse course = new RuralCourse();
        if (isCollected) {
            //已报课
            course = courseService.getDetailByUser(courseId, userId);
            course.setIsCollect(1);
        } else {
            //未报课
            course = courseService.getInfo(courseId);
            course.setIsCollect(0);
        }
        return Res.success(course);
    }

    /**
     * 报名课程 OR 取消报名课程
     *
     * @param pojo 实体
     * @return Res
     */
    @ApiOperation("报名课程 OR 取消报名课程")
    @PostMapping("/joinCourse")
    @ResponseBody
    public Res<Object> joinCourse(@RequestBody RuralCourseUser pojo) {
        Integer userId = JWTUtils.getAuthorId();
        pojo.setUserId(userId);
        if (pojo.getIsJoin() == 1 && courseUserService.isExists(pojo)) {
            return Res.error("你已报名该课程，请不要重复报名");
        }
        int ret = courseUserService.joinCourse(pojo);
        return ret > 0 ? pojo.getIsJoin() == 1 ? Res.success("报名成功") : Res.success("退课成功") : Res.error("操作失败");
    }

    @ApiOperation("用户记录视频时长")
    @PostMapping("/recordSchedule")
    @ResponseBody
    public Res<Object> recordVideoTime(@RequestBody RuralCourseUser pojo) {
        pojo.setUserId(JWTUtils.getAuthorId());
        RuralCourseUser ruralCourseUser = courseUserService.getByCourseAndUser(pojo);
        RuralCourse course = courseService.getById(pojo.getCourseId());
        //在做课节的时候，留意章节是否在关联表中被创建
        createChapterIfNotExist(pojo, course);
        int ret = 0;
        if (ruralCourseUser != null) {
            //更新学习时长
            int alreadyStudyTime = ruralCourseUser.getWatchTime() == null ? 0 : ruralCourseUser.getWatchTime();
            ruralCourseUser.setWatchTime(alreadyStudyTime + pojo.getWatchTime());
            //判断时长是否达到标准：>=视频时长
            if (ruralCourseUser.getWatchTime() >= course.getLessonVideoTime()) {
                //达到标准，更新状态
                ruralCourseUser.setIsPass(1);
            }
            ruralCourseUser.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
            ret = courseUserService.updateById(ruralCourseUser) ? 1 : 0;
        } else {
            pojo.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
            pojo.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
            if (pojo.getWatchTime() >= course.getLessonVideoTime()) {
                //达到标准，更新状态
                pojo.setIsPass(1);
            }
            ret += courseUserService.toInsert(pojo);
        }
        return ret > 0 ? Res.success("进度记录成功") : Res.error(ErrorEnum.SCHEDULE_RECORD_FAIL);
    }

    private void createChapterIfNotExist(RuralCourseUser pojo, RuralCourse course) {
        //判断章节是否在关联表中被创建
        RuralCourseUser ruralCourseUser = new RuralCourseUser();
        ruralCourseUser.setUserId(pojo.getUserId());
        ruralCourseUser.setCourseId(course.getCoursePid());
        if (!courseUserService.isExists(ruralCourseUser)) {
            //课节上的章节没有创建，则创建
            ruralCourseUser.setIsPass(0);
            ruralCourseUser.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
            ruralCourseUser.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
            courseUserService.toInsert(ruralCourseUser);
        }
    }

    private void createLesson(RuralCourseUser pojo) {
        pojo.setIsPass(0);
        pojo.setCreateTime(String.valueOf(System.currentTimeMillis() / 1000));
        pojo.setUpdateTime(String.valueOf(System.currentTimeMillis() / 1000));
        courseUserService.toInsert(pojo);
    }


    @ApiOperation("用户获取试卷（包含首次、再次答题）")
    @GetMapping("/getExamInfo")
    @ResponseBody
    public Res<Object> getCourseInfo(@RequestParam("course_id") Integer courseId) {
        int userId = JWTUtils.getAuthorId();
        //根据课节id获取课节信息 -> 然后获取该课节的试卷id
        RuralCourse course = courseService.getById(courseId);
        //封装用户和课节联表实体
        RuralCourseUser pojo = new RuralCourseUser();
        pojo.setUserId(userId);
        pojo.setCourseId(courseId);
        boolean isLessonExists = true;
        if (!courseUserService.isExists(pojo)){
            //创建之后MybatisPlus会主动为我们返回并装配给pojo对象
            createLesson(pojo);
            isLessonExists = false;
        }else{
            pojo = courseUserService.getByCourseAndUser(pojo);
        }
        //创建章节（若不存在）
        createChapterIfNotExist(pojo, course);
        //根据联表实体获取用户课节信息
        int examId = course.getCourseResource();
        //获取试卷实体
        RuralExamination exam = examinationService.getDetail(examId);
        /*
            获取试卷关联的题目列表
            并且按情况做修饰，然后得到list
            最后set进试卷实体中
         */
        List<Integer> ids = examQuestionService.getIdsByExamId(examId);
        List<RuralQuestion> list = new ArrayList<>();
        if (isLessonExists) {
            //该用户已经答过该试卷，则获取有部分答案的JSON（做过）并计算得分、通过状态、给出总分和通过分数
            //根据题目ids获取题目列表
            list = questionService.getListByUserAndExamIds(ids,pojo);
            exam.setUserScore(pojo.getUserScore() == null? -1.0: pojo.getUserScore());
            exam.setIsPass(Double.parseDouble(String.valueOf(exam.getExamPassScore())) <= pojo.getUserScore() ? 1 : 0);
            if (!exam.getIsPass().equals(pojo.getIsPass())) {
                //如果答题状态不一致，则更新答题状态
                pojo.setIsPass(exam.getIsPass());
                courseUserService.updateById(pojo);
            }
        }else{
            //该用户不存在答题记录，获取无答案的JSON，并给出总分和通过分数
            exam.setUserScore(-1.0);
            list = questionService.getListByIdsIgnoreCorrect(ids);
        }
        exam.setList(list);
        return Res.success(exam);
    }


    @ApiOperation("用户提交试卷")
    @PostMapping("/commitExam")
    @ResponseBody
    public Res<RuralCourseUser> commitExam(
            @RequestBody RuralCourseUser courseUser){
        //装配用户答题记录实体（userId，courseId，userAnswerBody）
        int userId = JWTUtils.getAuthorId();
        courseUser.setUserId(userId);
        /*
            判断是否通过（
            1.业务层根据实体中courseId查询rural_course表中的resource_id即examId，
            2.然后根据examId查询rural_question表中的答案集合
            3.最后做O2复杂度（双层for循环）判断，并执行修改联表实体的操作
            4.mybatisPlus会主动为我们返回并装配给courseUser对象，我们直接可以知道分数和通过状态
            ）
        */
        courseUserService.automaticReview(courseUser);
        //封装新的实体，并作为返回对象
        RuralCourseUser result = new RuralCourseUser();
        result.setUserScore(courseUser.getUserScore());
        result.setIsPass(courseUser.getIsPass());
        result.setTotalScore(courseUser.getTotalScore());
        result.setPassScore(courseUser.getPassScore());
        //return
        return result.getIsPass() == 1 ? Res.success(result,"测验通过！") : Res.error(result,"测验未通过！");
    }

    /**
     * 用户获取首页轮播
     *
     * @return 轮播列表
     */
    @ResponseBody
    @GetMapping("/getTabList")
    @ApiOperation("用户获取首页轮播")
    public Res<List<RuralTab>> getListTab() {
        List<RuralTab> list = tabService.getList();
        return Res.success(list);
    }

    /**
     * 用户获取课程轮播轮播
     *
     * @return 轮播列表
     */
    @ResponseBody
    @GetMapping("/getCourseTabList")
    @ApiOperation("用户获取课程轮播轮播")
    public Res<List<RuralTab>> getCourseTabList() {
        List<RuralTab> list = tabService.getCourseTabList();
        return Res.success(list);
    }

    @ResponseBody
    @GetMapping("/getAreaByAdCode")
    @ApiOperation("根据adcode获取地区")
    public Res<RuralArea> getAreaByAdcode(@RequestParam("adcode") String adCode) {
        RuralArea ruralArea = areaService.getByAdCode(adCode);
        return Res.success(ruralArea);
    }

    @ResponseBody
    @GetMapping("/getJsonByAdcode")
    @ApiOperation("根据adcode获取阿里Json详情")
    public Res<JSONObject> getJsonByAdcode(@RequestParam("adcode") String adCode) {

        String s = "";
        s = UrlUtils.sendGet("https://geo.datav.aliyun.com/areas_v3/bound/geojson?code="+adCode+"_full");
        if (StringUtils.isEmpty(s)){
            s = UrlUtils.sendGet("https://geo.datav.aliyun.com/areas_v3/bound/geojson?code="+adCode);
        }
        return Res.success(JSONObject.parseObject(s));
    }



}
